package rv32

import (
	"fmt"
	"risc-vm/common"
	"risc-vm/vm/rv32/cpu"
	"risc-vm/vm/rv32/mem"
	"risc-vm/vm/rv32/pe"
)

func loadPE(reader *common.FileReader) *pe.PE {
	res := pe.New()

	// ELF
	res.ELF = pe.ELF{}
	res.ELF.Magic, _ = reader.ReadUint32()
	if res.ELF.Magic != pe.MAGIC {
		fmt.Println("文件格式有误!")
		return nil
	}
	res.ELF.EI_Class, _ = reader.ReadUint8()
	res.ELF.EI_Data, _ = reader.ReadUint8()
	res.ELF.EI_Version, _ = reader.ReadUint8()
	res.ELF.EI_Pad, _ = reader.ReadUint8()
	res.ELF.Other1, _ = reader.ReadUint64()

	if res.ELF.EI_Data == 1 {
		fmt.Println("小端模式")
		reader.IsSwap = false
	} else if res.ELF.EI_Data == 2 {
		fmt.Println("大端模式端模式")
	} else {
		fmt.Println("ELF 端序无效")
		return nil
	}

	res.ELF.E_Type, _ = reader.ReadUint16()
	res.ELF.E_Machine, _ = reader.ReadUint16()
	res.ELF.E_Version, _ = reader.ReadUint32()
	res.ELF.E_Entry, _ = reader.ReadLong()
	res.ELF.E_Phoff, _ = reader.ReadLong()
	res.ELF.E_Shoff, _ = reader.ReadLong()
	res.ELF.E_Flags, _ = reader.ReadUint32()
	res.ELF.E_Ehsize, _ = reader.ReadUint16()
	res.ELF.E_Phentsize, _ = reader.ReadUint16()
	res.ELF.E_Phnum, _ = reader.ReadUint16()
	res.ELF.E_Shentsize, _ = reader.ReadUint16()
	res.ELF.E_Shnum, _ = reader.ReadUint16()
	res.ELF.E_Shstrndx, _ = reader.ReadUint16()

	// Section Headers
	res.SectionHeaders = make([]pe.SectionHeader, res.ELF.E_Shnum)
	for i := 0; i < int(res.ELF.E_Shnum); i++ {
		addr := int64(res.ELF.E_Shoff.Low32Int) + int64(i)*int64(res.ELF.E_Shentsize)
		res.SectionHeaders[i].Name, _ = reader.ReadAtUint32(addr)
		res.SectionHeaders[i].Type, _ = reader.ReadAtUint32(addr + 4)
		res.SectionHeaders[i].Flags, _ = reader.ReadAtLong(addr + 8)
		res.SectionHeaders[i].Addr, _ = reader.ReadAtLong(addr + 16)
		res.SectionHeaders[i].Offs, _ = reader.ReadAtLong(addr + 24)
		res.SectionHeaders[i].Size, _ = reader.ReadAtLong(addr + 32)
	}
	//fmt.Println(res.SectionHeaders)
	return res
}

func initMemory(m *mem.Memory, p *pe.PE, reader *common.FileReader) {
	//count := 0
	for _, item := range p.SectionHeaders {
		if (item.Flags.Low32Int>>1)&0x1 == 0x1 {
			if item.Type == 8 {
				// for .bss, load in zeroes, since it's not actually stored in the elf
				for i := 0; i < int(item.Size.Low32Int); i++ {
					addr := ((uint32(item.Addr.Low32Int&0x7FFFFFFF) + uint32(i)) >> 2)
					m.Write(addr, 0)
					//if count < 50 {
					//	fmt.Printf("1>> i:%d j:%d low:%d addr:%x val:%x\n", n, i, item.Addr.Low32Int, addr, m.Read(addr))
					//	count++
					//}
				}
			} else {
				for i := 0; i < int(item.Size.Low32Int); i++ {
					addr := (uint32(item.Addr.Low32Int&0x7FFFFFFF) + uint32(i)) >> 2
					oldVal := m.Read(addr)
					t, _ := reader.ReadAtUint8(int64(item.Offs.Low32Int) + int64(i))
					newVal := oldVal | uint32(t)<<((i&0x3)<<3)
					m.Write(addr, newVal)
					//if count < 50 {
					//	fmt.Printf("2>> i:%d j:%d low:%d addr:%x val:%x\n", n, i, item.Addr.Low32Int, addr, m.Read(addr))
					//	count++
					//}
				}
			}
		}
	}
}

func Run(reader *common.FileReader) {
	p := loadPE(reader)
	if p == nil {
		return
	}
	// 初始化内存：10M大小
	m := mem.New(10)
	initMemory(m, p, reader)
	// 初始化CPU
	c := cpu.New(m)
	// start running program
	c.PC = uint32(p.ELF.E_Entry.Low32Int)
	c.Run()
}
